﻿using System.Linq;
using System.Runtime.InteropServices;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using DG.Tweening;

public class PuzzleDragHelper : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
    public Vector2Int layout;
    public bool onList;
    public int pointingAnchor;
    public float space = 5f;
    public Vector2 imgOffset;
    public RectTransform content;
    public RectTransform workContent;
    public Transform readyContent;
    public ScrollRect scroll;
    public PuzzleDragHelperElement elementTemplate;
    public PuzzleDragHelperAnchor anchorTemplate;
    public List<PuzzleDragHelperElement> elementsInList = new List<PuzzleDragHelperElement>(); // 列表里碎片
    public List<PuzzleDragHelperElement> elementDataSet = new List<PuzzleDragHelperElement>(); // 碎片集合
    public List<PuzzleDragHelperAnchor> anchorDataSet = new List<PuzzleDragHelperAnchor>(); // 拼图区域锚点格子
    public SortedList<int, SortedSet<int>> puzzleMap = new SortedList<int, SortedSet<int>>(); // <格子id， 碎片id>

    public Dictionary<int, List<int>> groupDataSet = new Dictionary<int, List<int>>(); // 编组数据 <组id， 碎片id列表>
    // --------------
    private float listHeight = -1;
    private Vector2 elementSize;
    private Vector2 workContentSize;
    // --------------

    [Header("ceshi")]
    public Image bgImg;
    public Transform vectoryWindow;
    public PuzzleDragHelperElement[] gos;
    private void Awake()
    {
        bgImg = GetComponent<Image>();

        scroll = GetComponent<ScrollRect>();
        listHeight = content.sizeDelta.y;
        elementSize = (elementTemplate.transform as RectTransform).sizeDelta;
        workContentSize = workContent.sizeDelta;
    }

    void Start()
    {
        foreach (var item in gos)
        {
            AddListItem(item);
        }
        InitGrid();

        int index = 0;
        for (int i = 1; i <= layout.y; i++)
        {
            for (int j = 1; j <= layout.x; j++)
            {
                anchorDataSet[index].SetGridPos(new Vector2Int(j, i));
                elementDataSet[index].SetGridPos(new Vector2Int(j, i));
                index++;
            }
        }
    }

    // Update is called once per frame
    void Update()
    {

    }

    public void InitGrid()
    {
        for (int i = 0; i < layout.x * layout.y; i++)
        {
            PuzzleDragHelperAnchor anchor = Instantiate(anchorTemplate, workContent);
            anchor.gameObject.SetActive(true);
            anchor.id = i;
            anchor.helper = this;
            anchorDataSet.Add(anchor);
        }

    }

    public void AddListItem(PuzzleDragHelperElement item)
    {
        item.cachedTransform.SetParent(content, true);
        item.id = elementDataSet.Count;
        item.helper = this;
        elementDataSet.Add(item);
        elementsInList.Add(item);
        UpdateListContent();

    }


    /// <summary>
    /// 更新列表容器size和元素位置
    /// </summary>
    private void UpdateListContent()
    {
        elementsInList.Sort((a, b) => a.order.CompareTo(b.order));
        float width = elementSize.x + space;
        float height = elementSize.y;

        content.DOSizeDelta(new Vector2(elementsInList.Count * width, listHeight), 0.2f);
        Canvas.ForceUpdateCanvases();

        for (int i = 0; i < elementsInList.Count; i++)
        {
            elementsInList[i].MoveTarget(new Vector2((i + 0.5f - elementsInList.Count * 0.5f) * width, 0), -1);
        }

        ProcessGroup();
    }

    public void ElementDragEnter(PuzzleDragHelperElement item)
    {
        item.cachedTransform.SetParent(readyContent, true);
        foreach (var puzzle in elementDataSet)
        {
            puzzle.SetRaycast(false);
        }
    }


    public void ElementOnDrag(PuzzleDragHelperElement element)
    {

    }

    public void ElementDragExit(PuzzleDragHelperElement element)
    {

        foreach (var puzzle in elementDataSet)
        {
            puzzle.SetRaycast(true);
        }

        // 如果是满尺寸编组，则不会进行移动，后续处理可以跳过
        if (element.groupId != -1 && IsGroupFullRect(element.groupId))
        {
            return;
        }

        if (element.groupId == -1) // 没有编组，是独立碎片
        {
            if (pointingAnchor == -1)
            {
                if (onList)
                {
                    InList(element);
                }
                else
                {
                    InGrid(element, element.anchorId);
                }
            }
            else
            {
                InGrid(element, pointingAnchor);
            }
        }
        else
        {
            // 编组移动
            MoveGroup(element, pointingAnchor);
        }

        UpdateListContent();
    }

    void InList(PuzzleDragHelperElement element)
    {
        if (!elementsInList.Contains(element))
        {
            elementsInList.Add(element);
        }

        if (puzzleMap.ContainsKey(element.anchorId))
        {
            puzzleMap[element.anchorId].Remove(element.id);
        }
        element.cachedTransform.SetParent(content, true);
        element.order = element.cachedTransform.anchoredPosition.x;
        element.inGrid = false;
        element.anchorId = -1;
        element.groupId = -1;
    }

    void InGrid(PuzzleDragHelperElement element, int target)
    {
        if (target == -1)
        {
            InList(element);
            return;
        }

        if (target == element.anchorId)  // 目标和当前一致，相当于重置位置
        {
            element.MoveTarget(GetGridRealPostion(target), target);
            return;
        }

        if (puzzleMap.ContainsKey(element.anchorId))
        {
            puzzleMap[element.anchorId].Remove(element.id);
            if (puzzleMap[element.anchorId].Count <= 0)
            {
                puzzleMap.Remove(element.anchorId);
            }
        }
        if (puzzleMap.ContainsKey(target))
        {
            puzzleMap[target].Add(element.id);
        }
        else
        {
            puzzleMap.Add(target, new SortedSet<int>() { element.id });
        }
        element.cachedTransform.SetParent(readyContent, true);
        element.MoveTarget(GetGridRealPostion(target), target);
        element.anchorId = target;
        element.inGrid = true;
        if (elementsInList.Contains(element))
        {
            elementsInList.Remove(element);
        }

    }

    public Vector2 GetGridRealPostion(int anchor_id)
    {
        if (anchor_id != -1)
        {
            var anchor = anchorDataSet[anchor_id];
            return anchor.cachedTransform.anchoredPosition - workContentSize * 0.5f * new Vector2(1f, -1f);
        }
        return Vector2.zero;
    }


    int GetIDByGridPos(Vector2Int pos)
    {
        return (pos.y - 1) * layout.x + pos.x - 1;
    }

    /// <summary>
    /// 完成检测
    /// </summary>
    void ResultCheck()
    {
        if (puzzleMap.Count == (layout.x * layout.y) && groupDataSet.Count == 1)
        {
            foreach (var item in puzzleMap)
            {
                foreach (var element in item.Value)
                {
                    if (elementDataSet[element].gridPos != anchorDataSet[item.Key].gridPos)
                    {
                        return;
                    }
                }
            }
            vectoryWindow.DOScale(Vector3.one, 2f).SetEase(Ease.OutElastic);
        }
    }

    #region 编组

    /// <summary>
    /// 过滤所有碎片位置，进行编组
    /// </summary>
    void ProcessGroup()
    {
        // 检测碎片组合
        groupDataSet.Clear();

        foreach (var el in elementDataSet)
        {
            el.groupId = -1;
        }

        foreach (var aid in puzzleMap.Keys)
        {
            GroupGrow(aid);
        }

        void GroupGrow(int anchor_id)
        {
            PuzzleDragHelperElement element1;
            PuzzleDragHelperElement element2;
            PuzzleDragHelperAnchor anchor = anchorDataSet[anchor_id];
            foreach (var eid1 in puzzleMap[anchor_id])
            {
                element1 = elementDataSet[eid1];
                Vector2Int offset = anchor.gridPos - element1.gridPos;
                // if (element1.groupId != -1)
                // {
                //     continue;
                // }
                if (anchor.right != -1 && puzzleMap.ContainsKey(anchor.right))
                {
                    foreach (var eid2 in puzzleMap[anchor.right])
                    {
                        element2 = elementDataSet[eid2];
                        if (TakeGroup_Right(element1, element2) && (anchorDataSet[anchor.right].gridPos - element2.gridPos) == offset)
                        {
                            if (element2.groupId == -1)
                            {
                                GroupGrow(anchor.right);
                            }
                            AddGroup(element1, element2);
                            break;
                        }
                    }
                }
                if (anchor.buttom != -1 && puzzleMap.ContainsKey(anchor.buttom))
                {
                    foreach (var eid2 in puzzleMap[anchor.buttom])
                    {
                        element2 = elementDataSet[eid2];
                        if (TakeGroup_Buttom(element1, element2) && (anchorDataSet[anchor.buttom].gridPos - element2.gridPos) == offset)
                        {
                            if (element2.groupId == -1)
                            {
                                GroupGrow(anchor.buttom);
                            }
                            AddGroup(element1, element2);
                            break;
                        }
                    }
                }
            }
        }



        // 调整碎片遮挡层级
        List<List<int>> groups = groupDataSet.Values.ToList();
        groups.Sort((a, b) => a.Count.CompareTo(b.Count));

        foreach (var group in groups)
        {
            foreach (var eid in group)
            {
                elementDataSet[eid].cachedTransform.SetAsFirstSibling();
            }
        }

        ResultCheck();

    }

    // 编组方法
    bool TakeGroup_Right(PuzzleDragHelperElement element1, PuzzleDragHelperElement element2)
    {
        if ((element2.gridPos.x - element1.gridPos.x) == 1 && (element1.gridPos.y == element2.gridPos.y))
        {
            return true;
        }
        return false;
    }

    bool TakeGroup_Buttom(PuzzleDragHelperElement element1, PuzzleDragHelperElement element2)
    {
        if ((element2.gridPos.y - element1.gridPos.y) == 1 && (element1.gridPos.x == element2.gridPos.x))
        {
            return true;
        }
        return false;
    }


    /// <summary>
    /// 将两个元素编租
    /// </summary>
    /// <param name="element1"></param>
    /// <param name="element2"></param>
    void AddGroup(PuzzleDragHelperElement element1, PuzzleDragHelperElement element2)
    {
        int id = element1.groupId;
        if (id == -1)
            id = element2.groupId;
        if (id == -1)
            id = groupDataSet.Count;

        if (!groupDataSet.ContainsKey(id))
        {
            groupDataSet.Add(id, new List<int>());
        }

        if (!groupDataSet[id].Contains(element1.id))
            groupDataSet[id].Add(element1.id);
        if (!groupDataSet[id].Contains(element2.id))
            groupDataSet[id].Add(element2.id);
        element1.groupId = id;
        element2.groupId = id;

    }

    /// <summary>
    /// 移动编组
    /// </summary>
    void MoveGroup(PuzzleDragHelperElement leader, int target_anchor)
    {

        if (leader.anchorId == target_anchor || target_anchor == -1) // 锚点位置相等，没有移动格子，直接还原组内全部位置
        {
            foreach (var member in groupDataSet[leader.groupId])
            {
                PuzzleDragHelperElement element = elementDataSet[member];
                InGrid(element, element.anchorId);
            }
        }
        else
        {
            // 计算格子偏移量
            Vector2Int offset = anchorDataSet[leader.anchorId].gridPos - anchorDataSet[target_anchor].gridPos;
            // 超出边界的修正量
            Vector2Int revise = Vector2Int.zero;
            foreach (var eid in groupDataSet[leader.groupId])
            {
                var element = elementDataSet[eid];
                Vector2Int after_pos = anchorDataSet[element.anchorId].gridPos - offset;
                if (after_pos.x < 1)
                {
                    revise.x = Mathf.Max(1 - after_pos.x, revise.x);
                }
                else if (after_pos.x > layout.x)
                {
                    revise.x = Mathf.Min((after_pos.x - layout.x) * -1, revise.x);
                }

                if (after_pos.y < 1)
                {
                    revise.y = Mathf.Max(1 - after_pos.y, revise.y);
                }
                else if (after_pos.y > layout.y)
                {
                    revise.y = Mathf.Min((after_pos.y - layout.y) * -1, revise.y);
                }
            }
            offset = offset - revise;
            Vector2Int final_pos = Vector2Int.zero;
            foreach (var member in groupDataSet[leader.groupId])
            {
                PuzzleDragHelperElement element = elementDataSet[member];
                final_pos = anchorDataSet[element.anchorId].gridPos - offset;
                InGrid(element, GetIDByGridPos(final_pos));
            }
        }

    }

    /// <summary>
    /// 计算编组格子长宽
    /// </summary>
    /// <returns></returns>
    public Vector2Int GetGroupSize(int group_id)
    {
        if (groupDataSet.ContainsKey(group_id))
        {
            var groupData = groupDataSet[group_id];
            int left = layout.x;
            int right = 0;
            int top = layout.y;
            int buttom = 0;
            foreach (var eid in groupData)
            {
                var element = elementDataSet[eid];
                left = Mathf.Min(left, element.gridPos.x);
                right = Mathf.Max(right, element.gridPos.x);
                top = Mathf.Min(top, element.gridPos.y);
                buttom = Mathf.Max(buttom, element.gridPos.y);
            }
            return new Vector2Int(right - left + 1, buttom - top + 1);
        }
        return Vector2Int.zero;
    }

    /// <summary>
    /// 判断编组长宽是否满格
    /// </summary>
    /// <returns></returns>
    public bool IsGroupFullRect(int group_id)
    {
        Vector2Int size = GetGroupSize(group_id);
        if (size.x == layout.x && size.y == layout.y)
        {
            return true;
        }
        return false;
    }

    #endregion


    #region UI事件

    public void OnPointerEnter(PointerEventData eventData)
    {
        onList = true;
        bgImg.color = Color.yellow;
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        onList = false;
        bgImg.color = Color.white;
    }


    #endregion

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        foreach (var item in groupDataSet)
        {
            for (int i = 0; i < item.Value.Count - 1; i++)
            {
                PuzzleDragHelperElement el1 = elementDataSet[item.Value[i]];
                PuzzleDragHelperElement el2 = elementDataSet[item.Value[i + 1]];

                Gizmos.DrawLine(el1.transform.position, el2.transform.position);
            }
        }
    }

}
